fix: MCP auth proxy for transparent JWT refresh in long sessions#268
Merged
dimavedenyapin merged 8 commits intomainfrom Apr 26, 2026
Merged
fix: MCP auth proxy for transparent JWT refresh in long sessions#268dimavedenyapin merged 8 commits intomainfrom
dimavedenyapin merged 8 commits intomainfrom
Conversation
ACP, OpenCode, and Claude Code all bake MCP server headers at session start and never refresh them. After ~55 minutes the 1-hour JWT expires, causing persistent 401 errors on every MCP tool call with no recovery. This adds a local HTTP reverse proxy (127.0.0.1:<random port>) that intercepts MCP requests, calls enterpriseAuth.getJwt() for a fresh token on each request, and forwards to the real MCP server. The proxy decouples token lifetime from session lifetime. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
registerMcpProxyTarget is called on every buildMcpServersForAdapter, which runs per-prompt for Claude Code. Without dedup, each prompt creates a new target ID. Now returns the existing proxy URL if the same target URL was already registered. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs prevented MCP connection through the proxy: 1. Trailing slash: POST to /<id> produced target URL with trailing slash (e.g. /api/mcp/dev/mcp/) causing 404. Now uses target base URL as-is when there's no sub-path. 2. SSE buffering: deleting transfer-encoding header broke SSE event streaming. Now preserves it for text/event-stream responses and writes each chunk directly for immediate delivery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logs every incoming request, target resolution, upstream URL, and response status so we can see what's happening when the MCP client tries to connect through the proxy. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The proxy starts correctly but the Claude Code SDK never sends requests to the proxy URL — zero HTTP requests reach the handler. The SDK silently fails to establish an MCP transport through the proxy. Reverting to the original static JWT injection that works. The proxy code and tests remain in the codebase for future investigation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Routes [Workflo] MCP Dev Server through the local auth proxy (http://127.0.0.1:<port>/<id>) using type: 'http' (Streamable HTTP). Proxy injects fresh JWT on every request, decoupling token lifetime from session lifetime. Added logging of exact MCP config passed to claude binary for debugging. Added test-mcp-proxy-client.mjs script to manually verify proxy connectivity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The proxy was only started in index.ts during startup session restore. If the enterprise session wasn't cached (isAuthenticated: false), the proxy never started — even after the user logged in via ipc-handlers. Now startMcpAuthProxy() is also called in the enterprise login flow (ipc-handlers.ts) so it works regardless of startup state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce proxy logs to errors-only (startup + 404 + auth failures). Remove per-request logging and debug MCP config dump now that the proxy is verified working end-to-end. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mcp-auth-proxy.ts): local HTTP reverse proxy on127.0.0.1:<random port>that intercepts every MCP Streamable HTTP request, callsenterpriseAuth.getJwt()for a fresh JWT, and forwards to the real MCP server. Decouples token lifetime from session lifetime.[Workflo] MCP Dev Serverthrough the proxy instead of baking a static JWT at session start. Falls back to static JWT if proxy isn't running.Root cause of "errors that don't leave"
JWT has 1-hour lifetime. ACP/OpenCode/Claude Code bake MCP headers at session start and never refresh them. After ~55 minutes every MCP tool call gets 401 with no recovery path — the proxy fixes this transparently.
Test plan
🤖 Generated with Claude Code